package sncf.utils;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;

import org.apache.commons.logging.LogFactory;
import org.w3c.css.sac.CSSException;
import org.w3c.css.sac.CSSParseException;
import org.w3c.css.sac.ErrorHandler;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
import com.gargoylesoftware.htmlunit.IncorrectnessListener;
import com.gargoylesoftware.htmlunit.ScriptException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HTMLParserListener;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener;

public class WebTools {

	public static String getUrlContent(String url, String httpMethod,
			Map<String, String> params) {
		try {
			URL u = new URL(url);

			HttpURLConnection conn = null;

			ConfigLoader loaderInstance = ConfigLoader.getInstance();
			if (loaderInstance.get(ConfigLoader.PROXY_HOST_ADDRESS_PROPERTY) != null) {
				String host = (String) loaderInstance
						.get(ConfigLoader.PROXY_HOST_ADDRESS_PROPERTY);
				String port = (String) loaderInstance
						.get(ConfigLoader.PROXY_HOST_PORT_PROPERTY);

				Properties systemProperties = System.getProperties();
				systemProperties.setProperty("http.proxyHost", host);
				systemProperties.setProperty("http.proxyPort", port);

				if (loaderInstance.get(ConfigLoader.PROXY_USER_LOGIN_PROPERTY) != null) {
					final String login = (String) loaderInstance
							.get(ConfigLoader.PROXY_USER_LOGIN_PROPERTY);
					final String password = (String) loaderInstance
							.get(ConfigLoader.PROXY_USER_PASSWORD_PROPERTY);

					Authenticator authenticator = new Authenticator() {

						public PasswordAuthentication getPasswordAuthentication() {
							return (new PasswordAuthentication(login,
									password.toCharArray()));
						}

					};
					Authenticator.setDefault(authenticator);

					System.setProperty("http.proxyUser", login);
					System.setProperty("http.proxyPassword", password);
				}

				SocketAddress sa = new InetSocketAddress(host,
						Integer.parseInt(port));
				Type type = Type.HTTP;
				Proxy proxy = new Proxy(type, sa);
				conn = (HttpURLConnection) u.openConnection(proxy);
			} else {
				conn = (HttpURLConnection) u.openConnection();
			}
			conn.setRequestMethod(httpMethod);

			conn.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded");

			conn.setRequestProperty("Content-Language", "en-US");

			conn.setRequestProperty(
					"User-Agent",
					"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36");

			if (params != null && !params.isEmpty()) {
				String paramString = getParamString(params);

				if (paramString != null) {
					conn.setRequestProperty(
							"Content-Length",
							""
									+ Integer.toString(paramString.getBytes().length));
					conn.setUseCaches(false);
					conn.setDoInput(true);
					conn.setDoOutput(true);

					DataOutputStream wr = new DataOutputStream(
							conn.getOutputStream());

					wr.writeBytes(paramString);
					// System.out.println("Parameters string: " + paramString);
					wr.flush();
					wr.close();
				}

			}

			InputStream is = conn.getInputStream();
			ByteArrayOutputStream output = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			for (int bytesRead = 0; (bytesRead = is.read(buffer)) != -1;) {
				output.write(buffer, 0, bytesRead);
			}
			return output.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private static String getParamString(Map<String, String> params)
			throws UnsupportedEncodingException {
		String paramString = null;

		if (params != null) {
			Set<String> keySet = params.keySet();
			boolean first = true;
			for (String paramName : keySet) {
				if (!first) {
					paramString += "&";
				} else {
					paramString = "";
					first = false;
				}
				paramString += (URLEncoder.encode(paramName, "UTF-8") + "=" + URLEncoder
						.encode(params.get(paramName), "UTF-8"));
			}

		}

		return paramString;
	}

	public static String getWebContent(String url) {
		String pageAsXml = null;

		try {
			final WebClient webClient = new WebClient();
			HtmlPage page = webClient.getPage(url);
			pageAsXml = page.asXml();

			webClient.closeAllWindows();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return pageAsXml;
	}

	public static WebClient getWebClient() {
		return getWebClient(true, true);
	}

	public static WebClient getWebClient(boolean jsEnabled,
			boolean appletEnabled) {
		LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log",
				"org.apache.commons.logging.impl.NoOpLog");

		java.util.logging.Logger.getLogger("com.gargoylesoftware.htmlunit")
				.setLevel(Level.OFF);
		java.util.logging.Logger.getLogger("org.apache.commons.httpclient")
				.setLevel(Level.OFF);

		WebClient webClient = null;

		// set proxy
		ConfigLoader loaderInstance = ConfigLoader.getInstance();
		if (loaderInstance.get(ConfigLoader.PROXY_HOST_ADDRESS_PROPERTY) != null) {
			String proxyHost = (String) loaderInstance
					.get(ConfigLoader.PROXY_HOST_ADDRESS_PROPERTY);
			String port = (String) loaderInstance
					.get(ConfigLoader.PROXY_HOST_PORT_PROPERTY);

			int proxyPort = Integer.parseInt(port);

			String proxyUserName = null;
			String proxyPassword = null;

			if (loaderInstance.get(ConfigLoader.PROXY_USER_LOGIN_PROPERTY) != null) {
				proxyUserName = (String) loaderInstance
						.get(ConfigLoader.PROXY_USER_LOGIN_PROPERTY);
				proxyPassword = (String) loaderInstance
						.get(ConfigLoader.PROXY_USER_PASSWORD_PROPERTY);
			}

			webClient = new WebClient(BrowserVersion.CHROME, proxyHost,
					proxyPort);

			final DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient
					.getCredentialsProvider();
			credentialsProvider.addCredentials(proxyUserName, proxyPassword);

			String autoConfig = (String) loaderInstance
					.get(ConfigLoader.PROXY_AUTO_CONFIG_PROPERTY);
			if (autoConfig != null) {
				webClient.getOptions().getProxyConfig()
						.setProxyAutoConfigUrl(autoConfig);
			}
		} else {
			webClient = new WebClient(BrowserVersion.CHROME);
		}
		disableWebClientLogs(webClient);

		webClient.getCookieManager().setCookiesEnabled(true);
		webClient.getOptions().setJavaScriptEnabled(jsEnabled);
		webClient.getOptions().setTimeout(0);
		webClient.getOptions().setAppletEnabled(appletEnabled);

		return webClient;
	}

	private static void disableWebClientLogs(WebClient webClient) {

		webClient.setIncorrectnessListener(new IncorrectnessListener() {

			@Override
			public void notify(String arg0, Object arg1) {
				// TODO Auto-generated method stub

			}
		});
		webClient.setCssErrorHandler(new ErrorHandler() {

			@Override
			public void warning(CSSParseException exception)
					throws CSSException {
				// TODO Auto-generated method stub

			}

			@Override
			public void fatalError(CSSParseException exception)
					throws CSSException {
				// TODO Auto-generated method stub

			}

			@Override
			public void error(CSSParseException exception) throws CSSException {
				// TODO Auto-generated method stub

			}
		});
		webClient.setJavaScriptErrorListener(new JavaScriptErrorListener() {

			@Override
			public void timeoutError(HtmlPage arg0, long arg1, long arg2) {
				// TODO Auto-generated method stub

			}

			@Override
			public void malformedScriptURL(HtmlPage arg0, String arg1,
					MalformedURLException arg2) {
				// TODO Auto-generated method stub

			}

			@Override
			public void loadScriptError(HtmlPage arg0, URL arg1, Exception arg2) {
				// TODO Auto-generated method stub

			}

			@Override
			public void scriptException(HtmlPage htmlPage,
					ScriptException scriptException) {
				// TODO Auto-generated method stub

			}
		});
		webClient.setHTMLParserListener(new HTMLParserListener() {

			@Override
			public void error(String message, URL url, String html, int line,
					int column, String key) {
				// TODO Auto-generated method stub

			}

			@Override
			public void warning(String message, URL url, String html, int line,
					int column, String key) {
				// TODO Auto-generated method stub

			}
		});

	}

	public static void closeWebClient(WebClient webClient) {
		if (webClient != null) {
			webClient.close();
		}
	}

}
